package com.szgd.interceptor;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.security.core.userdetails.User;

import com.szgd.bean.AuthFilter;
import com.szgd.bean.AuthUser;
import com.szgd.util.BusinessName;
import com.szgd.util.ResBeanUtil;
import com.szgd.util.SessionUtil;
import com.szgd.util.StringUtil;
import com.szgd.util.UserUtil;

@Intercepts( {@Signature(
		type= Executor.class,
		method = "query",
		args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class AuthorityInterceptor implements Interceptor {
	static int MAPPED_STATEMENT_INDEX = 0;// 这是对应上面的args的序号
    static int PARAMETER_INDEX = 1;
    static int ROWBOUNDS_INDEX = 2;
    static int RESULT_HANDLER_INDEX = 3;
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		
		final Object[] queryArgs = invocation.getArgs();
        final MappedStatement mappedStatement = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
        final Object parameter = queryArgs[PARAMETER_INDEX];
        Map maps = new HashMap();
        if(parameter instanceof Map){
            maps = (Map) parameter;
        }
        final BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        String namespace = mappedStatement.getId();
        String className = namespace.substring(0,namespace.lastIndexOf("."));
        String methodName = namespace.substring(namespace.lastIndexOf(".") + 1,namespace.length());
        String remindType = "";
        if("com.szgd.dao.ecdata.personnel.RemindMapper".equals(className) && "getRemindData".equals(methodName)){
        	remindType = maps.get("remindType") == null ? "":maps.get("remindType").toString();
        }
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		List<AuthFilter> authList = null;
		ResultSet resultSet = null;
		try{
			connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
			String getAuthSql = "select CLASS_NAME,METHOD_NAME,COLUMN_NAME,FILTER_TYPE from SZGD_DATA_AUTHORITY_CFG where 1=1 and EFFECTIVEFLAG = '1' "
					+ "and CLASS_NAME = '" + className + "' and METHOD_NAME = '" + methodName + "'";
			if(StringUtil.isNotBlank(remindType)){
				getAuthSql += " and OTHER_FILTER = '" + remindType + "'";
			}
			preparedStatement = connection.prepareStatement(getAuthSql);
			resultSet = preparedStatement.executeQuery();
			authList = new ResBeanUtil().getList(AuthFilter.class, resultSet);
		


	//		StatementHandler handler =  (StatementHandler) invocation.getTarget();
	//		MetaObject metaObject = MetaObject.forObject(mappedStatement, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
	//		MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
	//		BoundSql boundSql = handler.getBoundSql();
			//获取参数列表
	//		Object parameterObject = boundSql.getParameterObject();
	//		String sqlId = mappedStatement.getId();
	//		String commandName = mappedStatement.getSqlCommandType().name();
			String newSql = "";
			if(authList != null && authList.size() != 0){
				Map<String,Object> map = new HashMap<String, Object>();
				if(parameter instanceof Map){
					map = (Map<String, Object>) parameter;
				}
				String isApp = map.get("isApp") == null ? "" : map.get("isApp").toString().replace("null","");
				String userId = map.get("userId") == null ? "" : map.get("userId").toString().replace("null","");
				
				
	//			CCJSqlParserManager sqlParserManager = new CCJSqlParserManager();
				//System.out.println(UserUtil.getUserInfomationBeanFromSession(SessionUtil.getSession()).getUsername());
				AuthFilter authMap = authList.get(0);
	//			String colunmName = authMap.get("COLUMN_NAME") == null ? "" : authMap.get("COLUMN_NAME").toString();
	//			String filterType = authMap.get("FILTER_TYPE") == null ? "" : authMap.get("FILTER_TYPE").toString();
				String colunmName = authMap.getCOLUMN_NAME() == null ? "" : authMap.getCOLUMN_NAME();
				String filterType = authMap.getFILTER_TYPE() == null ? "" : authMap.getFILTER_TYPE();
				Integer userid = null;
				String dept = "";
				if(StringUtil.isNotBlank(isApp) && "1".equals(isApp)){
					String sql = "SELECT LOGIN_ID,USER_NAME,DEPT_CD FROM SYS_USER WHERE USER_ID = "+userId;
					resultSet = connection.prepareStatement(sql).executeQuery();
					List<AuthUser> users = new ResBeanUtil().getList(AuthUser.class, resultSet);
					AuthUser authUser = users.get(0);
					userid = Integer.valueOf(userId);
					dept = authUser.getDEPT_CD();
				}else{
					User user = UserUtil.getUserInfomationBeanFromSession(SessionUtil.getSession());
					userid = user.getUserId();
					dept = user.getDeptCd();
				}
				//获取查询相关方法
				if(StringUtil.isNotBlank(colunmName) && StringUtil.isNotBlank(filterType)){
					if(BusinessName.USER_FILTER.getValue().equals(filterType)){
						String getUsersSql = "SELECT ''''||rtrim(xmlagg(xmlparse(content LOGIN_ID||''',''' wellformed) order by LOGIN_ID).getclobval(),''',''')||'''' from SYS_USER where DEPT_CD in"
								+ " (SELECT DEPT_CD FROM sys_dept START WITH DEPT_CD = "
								+ "'" + dept
								+ "' CONNECT BY PRIOR DEPT_ID = DEPT_PARENT_ID)"; 				
						
						resultSet = connection.prepareStatement(getUsersSql).executeQuery();
//						List<String> users = new ResBeanUtil().getList(String.class, resultSet);
//						if(users != null && users.size() != 0){
//							newSql = getNewSql(boundSql.getSql(),colunmName, users.get(0));
//						}
						String str = new ResBeanUtil().getListClob(resultSet);
						if(StringUtil.isNotBlank(str)){
							newSql = getNewSql(boundSql.getSql(),colunmName, str);
						}
					}else if(BusinessName.DEPT_FILTER.getValue().equals(filterType)){
						String getDeptsSql = "SELECT ''''||rtrim(xmlagg(xmlparse(content DEPT_CD||''',''' wellformed) order by DEPT_CD).getclobval(),''',''')||'''' FROM sys_dept START WITH DEPT_CD = "
								+ "'" + dept
								+ "' CONNECT BY PRIOR DEPT_ID = DEPT_PARENT_ID"; 				
						
						resultSet = connection.prepareStatement(getDeptsSql).executeQuery();
//						List<String> depts = new ResBeanUtil().getList(String.class, resultSet);
//						if(depts != null && depts.size() != 0){
//							newSql = getNewSql(boundSql.getSql(),colunmName, depts.get(0));
//						}
						String str = new ResBeanUtil().getListClob(resultSet);
						if(StringUtil.isNotBlank(str)){
							newSql = getNewSql(boundSql.getSql(),colunmName, str);
						}
					}else if(BusinessName.SITE_FILTER.getValue().equals(filterType)){
						String getSitesSql = "SELECT ''''||rtrim(xmlagg(xmlparse(content SITE_ID||''',''' wellformed) order by SITE_ID).getclobval(),''',''')||'''' FROM (SELECT SITE_ID FROM SZGD_SITE_USER_AUTH where USER_ID = "
								+ "'" + userid
								+ "' group by SITE_ID)"; 				
						
						resultSet = connection.prepareStatement(getSitesSql).executeQuery();
//						List<String> depts = new ResBeanUtil().getList(String.class, resultSet);
//						if(depts != null && depts.size() != 0){
//							newSql = getNewSql(boundSql.getSql(),colunmName, depts.get(0));
//						}
						String str = new ResBeanUtil().getListClob(resultSet);
						if(StringUtil.isNotBlank(str)){
							newSql = getNewSql(boundSql.getSql(),colunmName, str);
						}
					}else if(BusinessName.BID_FILTER.getValue().equals(filterType)){
						String getSitesSql = "SELECT ''''||rtrim(xmlagg(xmlparse(content BID_ID||''',''' wellformed) order by BID_ID).getclobval(),''',''')||'''' FROM (SELECT SZGD_SITE.BID_ID AS BID_ID FROM SZGD_SITE_USER_AUTH inner join SZGD_SITE on SZGD_SITE_USER_AUTH.SITE_ID = SZGD_SITE.id where USER_ID = "
								+ "'" + userid
								+ "' GROUP BY SZGD_SITE.BID_ID)"; 				
						
						resultSet = connection.prepareStatement(getSitesSql).executeQuery();
//						List<String> depts = new ResBeanUtil().getList(String.class, resultSet);
//						if(depts != null && depts.size() != 0){
//							newSql = getNewSql(boundSql.getSql(),colunmName, depts.get(0));
//						}
						String str = new ResBeanUtil().getListClob(resultSet);
						if(StringUtil.isNotBlank(str)){
							newSql = getNewSql(boundSql.getSql(),colunmName, str);
						}
					}
					else if(BusinessName.PERSON_FILTER.getValue().equals(filterType)){
						String getSitesSql = "SELECT id from (select id from SZGD_PERSONNEL_INFO where id not in (select PERSONNEL_ID from SZGD_PERSONNEL_FACE_ID)union all select id from SZGD_PERSONNEL_INFO where id in (select PERSONNEL_ID from SZGD_PERSONNEL_FACE_ID where SITE_ID in (select SITE_ID from SZGD_SITE_USER_AUTH where USER_ID = "
								+ "'" + userid
								+ "')))"; 				
//						
//						resultSet = connection.prepareStatement(getSitesSql).executeQuery();
//						List<String> depts = new ResBeanUtil().getList(String.class, resultSet);
//						if(depts != null && depts.size() != 0){
//							newSql = getNewSql(boundSql.getSql(),colunmName, depts.get(0));
//						}
//						String str = new ResBeanUtil().getListClob(resultSet);
						if(StringUtil.isNotBlank(getSitesSql)){
							newSql = getNewSql(boundSql.getSql(),colunmName, getSitesSql);
						}
					}
					
				}
			}
			//重新封装sql，用封装后的sql查询
			if(StringUtil.isNotBlank(newSql)){
				BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(),newSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
				MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));
				for (ParameterMapping mapping : boundSql.getParameterMappings()) {
		            String prop = mapping.getProperty();
		            if (boundSql.hasAdditionalParameter(prop)) {
		                newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
		            }
		        }
				queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
	//							ReflectHelper.setFieldValue(boundSql, "sql", newSql);
	//							metaObject.setValue("delegate.boundSql.sql", newSql);
			}
				
			return invocation.proceed();
		}finally{
			if (preparedStatement != null) {
				try {
					preparedStatement.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}


		}
	}

	@Override
	public Object plugin(Object arg0) {
		return Plugin.wrap(arg0, this);
	}

	@Override
	public void setProperties(Properties arg0) {
		// TODO Auto-generated method stub

	}
	
	private String getNewSql(String sql,String columnName,String objs){
		StringBuffer sqlAppend = new StringBuffer();
		sqlAppend.append(" select * from ( ");
		sqlAppend.append(sql);
		sqlAppend.append(" ) authFilter ");
		sqlAppend.append(" where authFilter.");
		sqlAppend.append(columnName);
		sqlAppend.append(" in (");
		sqlAppend.append(objs);
		sqlAppend.append(")");
		return sqlAppend.toString();
	}
	
	private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {
            builder.keyProperty(ms.getKeyProperties()[0]);
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }
	
	public static class BoundSqlSqlSource implements SqlSource {
        private BoundSql boundSql;
        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }
        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }
	
	private String getWhereInValuesSql(String column, String objs,int num) {
        // sql语句
        String sql = "(";
        // 值的个数
        String[] values = objs.split(",");
        int valueSize = values.length;
        // 批次数
        int batchSize = valueSize / num + (valueSize % num == 0 ? 0 : 1);
        for (int i = 0; i < batchSize; i++) {
            if (i > 0) {
                sql += ") or ";
            }
            sql += "authFilter."+column+" in (";
            for (int j = i * num; ( j < (i + 1) * num) && j < valueSize; j++) {
                if (j > i * num) {
                    sql += ",";
                }
                sql += values[j];
            }
        }
        sql += "))";
        return sql;
    }
}
